#include <strmif.h>
#include "mkvstream.hpp"
#include "mkvcontext.hpp"
#include <cassert>
#include <climits>


namespace MkvMux
{

MkvStream::Frame::Frame()
{
}


MkvStream::Frame::~Frame()
{
}


void MkvStream::Frame::Release()
{
   delete this;
}



MkvStream::MkvStream(MkvContext& c) :
    m_context(c),
    m_trackNumber(0)
{
}


MkvStream::~MkvStream()
{
}


void MkvStream::SetTrackNumber(int tn)
{
   m_trackNumber = tn;
}


int MkvStream::GetTrackNumber() const
{
   return m_trackNumber;
}


void MkvStream::WriteTrackEntry(int tn)
{
    EbmlIO::File& f = m_context.m_file;
    
    f.WriteID1(0xAE);  //TrackEntry ID (level 2)

    //allocate 2 bytes for track entry size field
    const __int64 begin_pos = f.SetPosition(2, STREAM_SEEK_CUR);

    WriteTrackNumber(tn);
    WriteTrackUID();
    WriteTrackType();    
    WriteTrackName();
    WriteTrackCodecID();
    WriteTrackCodecPrivate();
    WriteTrackCodecName();
    WriteTrackSettings();
    
    const __int64 end_pos = f.GetPosition();

    const __int64 size_ = end_pos - begin_pos;    
    assert(size_ <= USHRT_MAX);
    
    const USHORT size = static_cast<USHORT>(size_);
    
    f.SetPosition(begin_pos - 2);
    f.Write2UInt(size);
    
    f.SetPosition(end_pos);
}


void MkvStream::WriteTrackNumber(int tn_)
{
    EbmlIO::File& f = m_context.m_file;

    assert(tn_ > 0);
    assert(tn_ < 128);
    
    m_trackNumber = tn_;

    const BYTE tn = static_cast<BYTE>(tn_);
    
    f.WriteID1(0xD7);     //track number ID  //1101 0111
    f.Write1UInt(1);       
    f.Serialize1UInt(tn);
}    


void MkvStream::WriteTrackUID()
{
    EbmlIO::File& f = m_context.m_file;

    const TrackUID_t uid = CreateTrackUID();
    
    f.WriteID2(0x73C5);    //TrackUID ID
    f.Write1UInt(8);
    f.Serialize8UInt(uid);
}


void MkvStream::WriteTrackName()
{
}


void MkvStream::WriteTrackCodecPrivate()
{
}


void MkvStream::WriteTrackSettings()
{
}


MkvStream::TrackUID_t MkvStream::CreateTrackUID()
{
    TrackUID_t result;
    
    //NOTE: The TrackUID is serialized in the normal way (the same
    //as for any other integer that is the payload of an EBML tag),
    //but the Matroska spec does say that this is an unsigned 
    //integer.  In order to allow this integer value to be used
    //as an EBML varying-size integer, we restrict its value so
    //that it satifies the constraints for a varying size integer
    //that is streamed out using 8 bytes.  That means the upper
    //byte (the first in the stream) is 0 (the upper byte in the 
    //stream is reserved for indicating that this integer 
    //occupies 8 bytes total in the stream), and the low order
    //byte (the last in the stream) is even, which prevents
    //the integer from ever having a value with all bits set
    //(because then it would look like a signed integer).
    
    BYTE* p = reinterpret_cast<BYTE*>(&result);
    BYTE* const q = p + 7;
    
    {
        const int n = rand();
        
        BYTE& b0 = *p++;
        
        b0 = static_cast<BYTE>(n >> 4); //throw away low-order bits
        
        b0 &= 0xFE;  //ensure low order bit is not set
    }

    while (p != q)
    {
        const int n = rand();
        *p++ = static_cast<BYTE>(n >> 4); //throw away low-order bits
    }
    
    *p = 0;
    
    return result;
}


}  //end namespace MkvMux
